#include <windows.h>
#include <MSR_NuiApi.h>

HWND g_hWnd = NULL;

const int g_nWidth = 320;
const int g_nHeight = 240;

HANDLE g_hProcessStopEvent	= NULL;
HANDLE g_hNextDepthEvent	= NULL;
HANDLE g_hDepthStream		= NULL;

const int g_nEventCount = 2;
HANDLE g_hEvents[g_nEventCount] = {NULL, };

RGBQUAD g_rgbWk[g_nWidth*g_nHeight*4];

bool CreateNui()
{
	HRESULT hr = NuiInitialize(NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX);
	if(FAILED(hr))
	{
		MessageBox(NULL, L"NuiInitialize - Failed.", NULL, NULL);
		return false;
	}

	g_hNextDepthEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	hr = NuiImageStreamOpen(NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX, NUI_IMAGE_RESOLUTION_320x240,
		0, 2, g_hNextDepthEvent, &g_hDepthStream);
	if(FAILED(hr))
	{
		MessageBox(NULL, L"NuiImageStreamOpen - Failed.", NULL, NULL);
		return false;
	}

	g_hProcessStopEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

	g_hEvents[0] = g_hProcessStopEvent;
	g_hEvents[1] = g_hNextDepthEvent;

	return true;
}

void Draw(BYTE* pBuf)
{
	HDC hDC, memDC;
	HBITMAP hBmp, OldBmp;

	hDC = GetDC(g_hWnd);
	memDC = CreateCompatibleDC(hDC);
	hBmp = CreateCompatibleBitmap(hDC, g_nWidth, g_nHeight);
	
	SetBitmapBits(hBmp, g_nWidth*g_nHeight* 4, pBuf);
	OldBmp = (HBITMAP)SelectObject(memDC, hBmp);
	BitBlt(hDC, 0, 0, g_nWidth, g_nHeight, memDC, 0, 0, SRCCOPY);

	DeleteDC(memDC);
	DeleteObject(hBmp);
	ReleaseDC(g_hWnd, hDC);
}

RGBQUAD Short2Quad_Depth(USHORT s, short depth)
{
	USHORT RealDepth;
	USHORT Player = s & 7;
	
	if(depth >= 0)
		RealDepth = (s & 0xfff8) >> depth;
	else
		RealDepth = (s & 0xfff8) << (depth *= -1);	

	BYTE l = 255 - (BYTE)(256*RealDepth/0xffff);
	
	RGBQUAD q = {0, 0, 0, 0};

	switch(Player)
	{
	case 0:
		q.rgbRed = q.rgbGreen = q.rgbBlue = l / 2;
		break;
	case 1:
		q.rgbRed = l;
		break;
	case 2:
		q.rgbGreen = l;
		break;
	case 3:
		q.rgbRed = l / 4;
		q.rgbGreen = q.rgbBlue = l;
		break;
	case 4:
		q.rgbRed = q.rgbGreen = l;
		q.rgbBlue = l / 4;
		break;
	case 5:
		q.rgbRed = q.rgbBlue = l;
		q.rgbGreen = l / 4;
		break;
	case 6:
		q.rgbRed = q.rgbGreen = l / 2;
		q.rgbBlue = l;
		break;
	case 7:
		q.rgbRed = q.rgbGreen = q.rgbBlue = 255 - (l / 2);
		break;
	}

	return q;
}

void UpdateNui()
{
	int nEventIndex = WaitForMultipleObjects(g_nEventCount, g_hEvents, FALSE, 100);
	
	if(nEventIndex == 0)
		return;
	else
	{
		const NUI_IMAGE_FRAME *pImageFrame = NULL;

		if(FAILED(NuiImageStreamGetNextFrame(g_hDepthStream, 0, &pImageFrame)))
			return;

		KINECT_LOCKED_RECT LockedRect;
		pImageFrame->pFrameTexture->LockRect(0, &LockedRect, 0, 0);
		if(LockedRect.Pitch != 0)
		{
			BYTE	*pBuffer	= (BYTE*)LockedRect.pBits;
			RGBQUAD	*rgbRun		= g_rgbWk;
			USHORT	*pBufferRun	= (USHORT*)pBuffer;
			for(int y = 0; y < g_nHeight; y++)
				for(int x = 0; x < g_nWidth; x++)
				{
					RGBQUAD quad = Short2Quad_Depth(*pBufferRun, -1);
					pBufferRun++;
					*rgbRun = quad;
					rgbRun++;
				}

			Draw((BYTE*)g_rgbWk);
		}

		NuiImageStreamReleaseFrame(g_hDepthStream, pImageFrame);
	}
}

void DestroyNui()
{
	if(g_hProcessStopEvent)
	{
		CloseHandle(g_hProcessStopEvent);
		g_hProcessStopEvent = NULL;
	}

	NuiShutdown();

	if(g_hNextDepthEvent && (g_hNextDepthEvent != INVALID_HANDLE_VALUE))
	{
		CloseHandle(g_hNextDepthEvent);
		g_hNextDepthEvent = NULL;
	}
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	}

	return DefWindowProcA(hWnd, uMsg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
	LPCWSTR lpClassName = L"ex2_Depth";

	WNDCLASS wc = { CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0,
		hInstance, LoadIcon(NULL, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW),
		(HBRUSH)GetStockObject(WHITE_BRUSH), NULL, lpClassName};
	RegisterClass(&wc);

	RECT	rtWnd = {0, 0, g_nWidth, g_nHeight};
	DWORD	dwStyle = WS_OVERLAPPEDWINDOW;
	AdjustWindowRect(&rtWnd, dwStyle, FALSE);

	g_hWnd = CreateWindow(lpClassName, lpClassName, dwStyle,
		CW_USEDEFAULT, CW_USEDEFAULT, rtWnd.right - rtWnd.left, rtWnd.bottom - rtWnd.top,
		NULL, NULL, wc.hInstance, NULL);
	ShowWindow(g_hWnd, SW_SHOW);
	UpdateWindow(g_hWnd);

	MSG msg;
	ZeroMemory(&msg, sizeof(MSG));

	if(CreateNui())
	{
		while(msg.message != WM_QUIT)
		{
			if(PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
			{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
			else
				UpdateNui();
		}
		DestroyNui();
	}

	UnregisterClass(lpClassName, wc.hInstance);
	return (int)msg.wParam;
}